package org.zhq.server;


import org.zhq.constants.UDPConstants;
import org.zhq.util.ByteUtils;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.nio.ByteBuffer;
import java.util.UUID;

/**
 * @author zhengquan
 * @date 2018/12/22
 */
public class UDPProvider {

    private static Provider PROVIDER_INSTANCE;


    public static void start(int port) {
        stop();
        String sn = UUID.randomUUID().toString();
        Provider provider = new Provider(sn.getBytes(), port);
        provider.start();
        PROVIDER_INSTANCE = provider;
    }

    public static void stop() {
        if (PROVIDER_INSTANCE != null) {
            PROVIDER_INSTANCE.exit();
            PROVIDER_INSTANCE = null;
        }
    }

    private static class Provider extends Thread {
        private final byte[] sn;
        private final int port;
        private boolean done = false;
        private DatagramSocket ds = null;

        final byte[] buffer = new byte[512];

        public Provider(byte[] sn, int port) {
            super("UPProvider-Listener-Thread");
            this.sn = sn;
            this.port = port;
        }

        @Override
        public void run() {
            super.run();

            System.out.println("UDPProvider started");

            try {
                //监听30201端口
                ds = new DatagramSocket(UDPConstants.PORT_SERVER);

                DatagramPacket receivePack = new DatagramPacket(buffer, buffer.length);
                while (!done) {
                    //接收信息
                    ds.receive(receivePack);

                    //打印接收到的信息与发送者信息
                    //发送者的IP地址
                    String clientIp = receivePack.getAddress().getHostAddress();
                    int clientPort = receivePack.getPort();
                    int dataLen = receivePack.getLength();
                    byte[] data = receivePack.getData();
                    boolean isValid = (UDPConstants.HEADER.length + 2 + 4) <= dataLen && ByteUtils.startWith(data, UDPConstants.HEADER);
                    System.out.println("UDPProvider receive from ip:" + clientIp + " port:" + clientPort + " data:" + data + " isValid:" + isValid);

                    if (!isValid) {
                        //无效继续
                        continue;
                    }

                    //解析命令与回送端口
                    int index = UDPConstants.HEADER.length;
                    short cmd = (short) ((data[index++] << 8) | (data[index++] & 0xff));
                    int responsePort = (data[index++] << 24 |
                            (data[index++] & 0xff) << 16 |
                            (data[index++] & 0xff) << 8 |
                            (data[index++] & 0xff));
                    //判断合法性
                    if (cmd == 1 && responsePort > 0) {
                        //构建一份回送数据
                        ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
                        byteBuffer.put(UDPConstants.HEADER);
                        byteBuffer.putShort((short) 2);
                        byteBuffer.putInt(port);
                        byteBuffer.put(sn);
                        int len = byteBuffer.position();
                        //直接根据发送者构建一份回送信息
                        DatagramPacket responsePacket = new DatagramPacket(buffer, len, receivePack.getAddress(), responsePort);
                        ds.send(responsePacket);

                        System.out.println("UDPProvider response to:" + clientIp + " port:" + responsePort);
                    } else {
                        System.out.println("UDPProvider receive cmd nonsupport;cmd:" + cmd + "port:" + responsePort);
                    }
                }
            } catch (Exception ignore) {

            } finally {
                close();
            }

            System.out.println("UDPProvider finished");
        }

        void close() {
            if (ds != null) {
                ds.close();
                ds = null;
            }
        }


        void exit() {
            done = true;
            close();
        }

    }
}
